﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WebSocketSharp.Server;

namespace DetectorReader
{
    public partial class Form1 : Form
    {
        [DllImport("modbuswrraper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        private static extern bool create_modbus_client(string port_name, int baudrate);

        [DllImport("modbuswrraper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        private static extern void set_slave(int slaveId);

        [DllImport("modbuswrraper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        private static extern int read_detector(int detector_address, int detector_count, [Out][MarshalAs(UnmanagedType.LPArray)] float[] values, StringBuilder errmsg);

        [DllImport("modbuswrraper.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        private static extern void stop_modbus();

        private List<ControlHost> hosts;
        private AutoResetEvent exitEvent;
        private delegate void PrintMsgNotInUiThread(string msg);
        private WebSocketDataSender dataSender;
        private int waitMilliSec;

        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            MaximizeBox = false;
            FormBorderStyle = FormBorderStyle.FixedSingle;
            numericUpDown1.Value = 300;
            numericUpDown1.Maximum = 10000;
            numericUpDown1.Minimum = 100;
            numericUpDown2.Value = 1;
            numericUpDown2.Maximum = 10;
            numericUpDown2.Minimum = 1;
            waitMilliSec = 1000;
            InitCompoBox();
            try
            {
                int port = 9600;
                dataSender = new WebSocketDataSender(port, PrintMsgInChildThread);
                PrintMsg($"websocket服务启动成功,端口:{port}");
            }
            catch (Exception ex)
            {
                PrintErrMsg($"websocket服务启动异常,{ex.Message}");
            }
        }

        void InitCompoBox()
        {
            var names = SerialPort.GetPortNames();
            comboBox1.DataSource = names;
        }

        void PrintMsgInChildThread(string msg)
        {
            richTextBox1.BeginInvoke(new PrintMsgNotInUiThread(PrintMsg), msg);
        }
        void PrintErrorMsgInChildThread(string msg)
        {
            richTextBox1.BeginInvoke(new PrintMsgNotInUiThread(PrintErrMsg), msg);
        }

        void PrintErrMsg(string msg)
        {
            msg = $"[{DateTime.Now.ToString("F")}](发生异常)-{msg}\n\n";

            richTextBox1.SelectionStart = richTextBox1.TextLength;
            richTextBox1.SelectionLength = 0;
            richTextBox1.SelectionColor = Color.Red;
            richTextBox1.AppendText(msg);
            richTextBox1.SelectionColor = richTextBox1.ForeColor;

            richTextBox1.ScrollToCaret();
        }
        void PrintMsg(string msg)
        {
            msg = $"[{DateTime.Now.ToString("F")}]-{msg}\n";
            richTextBox1.AppendText(msg);
            richTextBox1.ScrollToCaret();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var portname = comboBox1.SelectedItem?.ToString();
            if (string.IsNullOrEmpty(portname))
            {
                PrintMsg("请先选择数据读取串口");
                return;
            }
            try
            {
                string text = System.IO.File.ReadAllText("config.json", Encoding.UTF8);
                hosts = JsonConvert.DeserializeObject<List<ControlHost>>(text);

            }
            catch (Exception ex)
            {
                PrintErrMsg("读取控制器信息失败," + ex.Message);
                return;
            }

            if (hosts.Any(host => host.PointCount != host.PointNames.Length))
            {
                PrintErrMsg("配置文件检查发现错误,控制器名称和数量不一致");
                return;
            }

            if (!create_modbus_client(portname, 9600))
            {
                PrintErrMsg("连接串口异常,请检查串口名称是否正确以及是否已被占用");
                return;
            }

            exitEvent = new AutoResetEvent(false);
            button1.Enabled = false;
            new Task(ReadDetectors).Start();
        }

        void ReadDetectors()
        {
            while (true)
            {
                if (exitEvent.WaitOne(waitMilliSec))
                {
                    exitEvent = null;
                    break;
                }
                foreach (ControlHost host in hosts)
                {
                    set_slave(host.Address);
                    float[] values = new float[host.PointCount];
                    StringBuilder err = new StringBuilder();

                    int ret = read_detector(1, host.PointCount, values, err);
                    if (ret <= 0)
                    {
                        PrintErrorMsgInChildThread(host.Position + "主机" + err.ToString());
                        dataSender.Send(BuildFailPushData(host, err.ToString()));
                        continue;
                    }
                    PrintMsgInChildThread(BuildDetectorInfoMsg(host, values));
                    dataSender.Send(BuildSuccessPushData(host, values));
                }
            }
        }

        string BuildDetectorInfoMsg(ControlHost host, float[] values)
        {
            if (values.Length != host.PointNames.Length)
                return $"数据与点位数量不一致,数据数量:${values.Length},点位名称数量:${host.PointNames.Length}";

            StringBuilder builder = new StringBuilder();
            builder.Append($"{host.Position}数据:\n");
            for (int i = 0; i < values.Length; i++)
                builder.Append($"{host.PointNames[i]}={values[i]}  ");
            builder.Append("\n");
            return builder.ToString();
        }

        string BuildSuccessPushData(ControlHost host, float[] values)
        {
            if (values.Length != host.PointNames.Length)
                return $"数据与点位数量不一致,数据数量:${values.Length},点位名称数量:${host.PointNames.Length}";
            WorkShopData workShopData = new WorkShopData();
            workShopData.success = true;
            workShopData.workshopName = host.Position;
            for (int i = 0; i < values.Length; i++)
                workShopData.detectorValues.Add(new DetectorValue(host.PointNames[i], values[i]));
            return JsonConvert.SerializeObject(workShopData);
        }

        string BuildFailPushData(ControlHost host, string errmsg)
        {
            WorkShopData workShopData = new WorkShopData();
            workShopData.success = false;
            workShopData.errmsg = errmsg;
            workShopData.workshopName = host.Position;
            return JsonConvert.SerializeObject(workShopData);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (exitEvent != null)
            {
                exitEvent.Set();
                stop_modbus();
                PrintMsg("停止监控");
                button1.Enabled = true;
            }
            GC.Collect();
            GC.WaitForPendingFinalizers();

        }

        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            if (richTextBox1.Lines.Length > numericUpDown1.Value)
            {
                richTextBox1.Clear();
            }
        }

        private void numericUpDown2_ValueChanged(object sender, EventArgs e)
        {
            waitMilliSec = (int)numericUpDown2.Value * 1000;
        }

        

    }
}
